Supervised Learning : Convolutional Neural Network Frameworks for Multi-Class Image Classification¶


John Pauline Pineda

December 25, 2023


  • 1. Table of Contents
    • 1.1 Data Background
    • 1.2 Data Description
    • 1.3 Data Quality Assessment
    • 1.4 Data Preprocessing
      • 1.4.1 Image Description
      • 1.4.2 Image Augmentation
    • 1.5 Data Exploration
      • 1.5.1 Exploratory Data Analysis
    • 1.6 Model Development
      • 1.6.1 Premodelling Data Description
      • 1.6.2 CNN With No Regularization
      • 1.6.3 CNN With Dropout Regularization
      • 1.6.4 CNN With Batch Normalization Regularization
      • 1.6.5 CNN With Dropout and Batch Normalization Regularization
    • 1.7 Consolidated Findings
  • 2. Summary
  • 3. References

1. Table of Contents ¶

This project explores the various convolutional neural network (CNN) frameworks for processeing images through convolutional, activation, pooling, and fully connected layers, capturing hierarchical features and learning to map input images to their respective classes during training using various helpful packages in Python. Various CNN architectures applied in the analysis to learn features and patterns at different levels of abstraction in images included CNN Without Regularization, CNN With Dropout Regularization, CNN With Batch Normalization Regularization and CNN With Dropout and Batch Normalization Regularization. The different CNN algorithms were evaluated using the categorical cross entropy loss which measures the difference between the predicted probability distribution and the true distribution of the class labels. Model multi-classification performance was measured using Accuracy, Precision, Recall and F1 Score. All results were consolidated in a Summary presented at the end of the document.

A convolutional neural network model is a type of neural network architecture specifically designed for image classification and computer vision tasks by automatically learning hierarchical features directly from raw pixel data. The core building block of a CNN is the convolutional layer. Convolution operations apply learnable filters (kernels) to input images to detect patterns such as edges, textures, and more complex structures. The layers systematically learn hierarchical features from low-level (e.g., edges) to high-level (e.g., object parts) as the network deepens. Filters are shared across the entire input space, enabling the model to recognize patterns regardless of their spatial location. After convolutional operations, an activation function is applied element-wise to introduce non-linearity and allow the model to learn complex relationships between features. Pooling layers downsample the spatial dimensions of the feature maps, reducing the computational load and the number of parameters in the network - creating spatial hierarchy and translation invariance. Fully connected layers process the flattened features to make predictions and produce an output vector that corresponds to class probabilities using an activation function. The CNN is trained using backpropagation and optimization algorithms. A loss function is used to measure the difference between predicted and actual labels. The network adjusts its weights to minimize this loss. Gradients are calculated with respect to the loss, and the weights are updated accordingly through a backpropagation mechanism.

1.1. Data Background ¶

A subset of an open COVID-19 Radiography Dataset from Kaggle (with all credits attributed to Preet Viradiya, Juliana Negrini De Araujo, Tawsifur Rahman, Muhammad Chowdhury and Amith Khandakar) was used for the analysis as consolidated from the following primary sources:

  1. Covid19 X-Ray Images from BIMCV Medical Imaging Databank of the Valencia Region
  2. Covid19 X-Ray Images from GitHub: ML Group
  3. Covid19 X-Ray Images from Italian Society of Medical and Interventional Radiology
  4. Covid19 X-Ray Images from European Society of Radiology
  5. Covid19 X-Ray Images from GitHub: Joseph Paul Cohen
  6. Covid19 X-Ray Images from Publication: COVID-CXNet: Detecting COVID-19 in Frontal Chest X-ray Images using Deep Learning
  7. Pneumonia and Normal X-Ray Images from Kaggle: RSNA Pneumonia Detection Challenge
  8. Pneumonia and Normal X-Ray Images from Kaggle: Chest X-Ray Images (Pneumonia)

This study hypothesized that images contain a hierarchy of features which allows the differentiation and classification across various image categories.

The target variable for the study is:

  • CLASS - Multi-categorical diagnostic classification for the x-ray images

The hierarchical representation of image features enables the network to transform raw pixel data into a meaningful and compact representation, allowing it to make accurate predictions during image classification. The different features automatically learned during the training process are as follows:

  • LOW-LEVEL FEATURES - Edges and textures
  • MID-LEVEL FEATURES - Patterns and shapes
  • HIGH-LEVEL FEATURES - Object parts
  • ABSTRACT FEATURES - Object semantics
  • SEMANTIC CONCEPTS - Object categories
  • HIERARCHICAL REPRESENTATION - Spatial hierarchy
  • ROTATION | SCALE INVARIANCE - Invariant features
  • LOCALIZATION INFORMATION - Spatial localization

1.2. Data Description ¶

  1. The dataset is comprised of:
    • 3600 images (observations)
    • 1 target (variable)
      • CLASS: COVID = 1200 images
      • CLASS: Normal = 1200 images
      • CLASS: Viral Pneumonia = 1200 images
In [1]:
##################################
# Installing important packages
##################################
# !pip install mlxtend
# !pip install --upgrade tensorflow
# !pip install opencv-python
# !pip install keras==2.12.0
In [2]:
##################################
# Loading Python Libraries 
# for Data Loading,
# Data Preprocessing and
# Exploratory Data Analysis
##################################
import numpy as np
import pandas as pd 
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
%matplotlib inline
import tensorflow as tf
import keras
from PIL import Image
from glob import glob
import cv2
import os
import random
WARNING:tensorflow:From C:\Users\John pauline magno\AppData\Roaming\Python\Python311\site-packages\keras\losses.py:2664: The name tf.losses.sparse_softmax_cross_entropy is deprecated. Please use tf.compat.v1.losses.sparse_softmax_cross_entropy instead.

In [3]:
##################################
# Loading Python Libraries 
# for Model Development
##################################
from keras import backend as K
from keras import regularizers
from keras.models import Sequential, Model,load_model
from keras.layers import Activation, Dense, Dropout, Flatten, Conv2D, MaxPooling2D, MaxPool2D, AveragePooling2D, GlobalMaxPooling2D, BatchNormalization
from keras.wrappers.scikit_learn import KerasClassifier
from keras.utils.np_utils import to_categorical
from keras.optimizers import Adam, SGD
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import ReduceLROnPlateau, EarlyStopping, ModelCheckpoint
from tensorflow.keras.utils import img_to_array, array_to_img
In [4]:
##################################
# Loading Python Libraries 
# for Model Evaluation
##################################
from keras.metrics import PrecisionAtRecall, Recall 
from sklearn.metrics import confusion_matrix
from sklearn.metrics import precision_recall_fscore_support, accuracy_score
In [5]:
##################################
# Setting random seed options
# for the analysis
##################################
def set_seed(seed=88888888):
    np.random.seed(seed) 
    tf.random.set_seed(seed) 
    keras.utils.set_random_seed(seed)
    random.seed(seed)
    tf.config.experimental.enable_op_determinism()
    os.environ['TF_DETERMINISTIC_OPS'] = "1"
    os.environ['TF_CUDNN_DETERMINISM'] = "1"
    os.environ['PYTHONHASHSEED'] = str(seed)

set_seed()
In [6]:
##################################
# Loading the dataset
##################################
path = 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset/'

##################################
# Defining the image category levels
##################################
diagnosis_code_dictionary = {'COVID': 0,
                             'Normal': 1,
                             'Viral Pneumonia': 2}

##################################
# Defining the image category descriptions
##################################
diagnosis_description_dictionary = {'COVID': 'Covid-19',
                                    'Normal': 'Healthy',
                                    'Viral Pneumonia': 'Viral Pneumonia'}

##################################
# Consolidating the image path
##################################
imageid_path_dictionary = {os.path.splitext(os.path.basename(x))[0]: x for x in glob(os.path.join(path, '*','*.png'))}
In [7]:
##################################
# Taking a snapshot of the dictionary
##################################
dict(list(imageid_path_dictionary.items())[0:5]) 
Out[7]:
{'COVID-1': 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset\\COVID\\COVID-1.png',
 'COVID-10': 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset\\COVID\\COVID-10.png',
 'COVID-100': 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset\\COVID\\COVID-100.png',
 'COVID-1000': 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset\\COVID\\COVID-1000.png',
 'COVID-1001': 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset\\COVID\\COVID-1001.png'}
In [8]:
##################################
# Consolidating the information
# from the dataset
# into a dataframe
##################################
xray_images = pd.DataFrame.from_dict(imageid_path_dictionary, orient = 'index').reset_index()
xray_images.columns = ['Image_ID','Path']
classes = xray_images.Image_ID.str.split('-').str[0]
xray_images['Diagnosis'] = classes
xray_images['Target'] = xray_images['Diagnosis'].map(diagnosis_code_dictionary.get) 
xray_images['Class'] = xray_images['Diagnosis'].map(diagnosis_description_dictionary.get) 
In [9]:
##################################
# Performing a general exploration of the dataset
##################################
print('Dataset Dimensions: ')
display(xray_images.shape)
Dataset Dimensions: 
(3600, 5)
In [10]:
##################################
# Listing the column names and data types
##################################
print('Column Names and Data Types:')
display(xray_images.dtypes)
Column Names and Data Types:
Image_ID     object
Path         object
Diagnosis    object
Target        int64
Class        object
dtype: object
In [11]:
##################################
# Taking a snapshot of the dataset
##################################
xray_images.head()
Out[11]:
Image_ID Path Diagnosis Target Class
0 COVID-1 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19
1 COVID-10 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19
2 COVID-100 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19
3 COVID-1000 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19
4 COVID-1001 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19
In [12]:
##################################
# Performing a general exploration of the numeric variables
##################################
print('Numeric Variable Summary:')
display(xray_images.describe(include='number').transpose())
Numeric Variable Summary:
count mean std min 25% 50% 75% max
Target 3600.0 1.0 0.81661 0.0 0.0 1.0 2.0 2.0
In [13]:
##################################
# Performing a general exploration of the object variable
##################################
print('Object Variable Summary:')
display(xray_images.describe(include='object').transpose())
Object Variable Summary:
count unique top freq
Image_ID 3600 3600 COVID-1 1
Path 3600 3600 C:/Users/John pauline magno/Python Notebooks/C... 1
Diagnosis 3600 3 COVID 1200
Class 3600 3 Covid-19 1200
In [14]:
##################################
# Performing a general exploration of the target variable
##################################
xray_images.Diagnosis.value_counts()
Out[14]:
COVID              1200
Normal             1200
Viral Pneumonia    1200
Name: Diagnosis, dtype: int64
In [15]:
##################################
# Performing a general exploration of the target variable
##################################
xray_images.Diagnosis.value_counts(normalize=True)
Out[15]:
COVID              0.333333
Normal             0.333333
Viral Pneumonia    0.333333
Name: Diagnosis, dtype: float64

1.3. Data Quality Assessment ¶

Data quality findings based on assessment are as follows:

  1. No duplicated images observed.
  2. No null images observed.
In [16]:
##################################
# Counting the number of duplicated images
##################################
xray_images.duplicated().sum()
Out[16]:
0
In [17]:
##################################
# Gathering the number of null images
##################################
xray_images.isnull().sum()
Out[17]:
Image_ID     0
Path         0
Diagnosis    0
Target       0
Class        0
dtype: int64

1.4. Data Preprocessing ¶

1.4.1 Image Description ¶

  1. Each image contains 3 channels:
    • 1.1 Red channel pixel value range = 0 to 255
    • 1.2 Blue channel pixel value range = 0 to 255
    • 1.3 Green channel pixel value range = 0 to 255
  2. Each images is in gray scale indicating that the values for each individual channel are exactly the same.
    • 2.1 Image height = 299 pixels
    • 2.2 Image width = 299 pixels
    • 2.3 Image size = 268203 pixels
In [18]:
##################################
# Including the pixel information
# of the actual images
# in array format
# into a dataframe
##################################
xray_images['Image'] = xray_images['Path'].map(lambda x: np.asarray(Image.open(x).resize((75,75))))
In [19]:
##################################
# Listing the column names and data types
##################################
print('Column Names and Data Types:')
display(xray_images.dtypes)
Column Names and Data Types:
Image_ID     object
Path         object
Diagnosis    object
Target        int64
Class        object
Image        object
dtype: object
In [20]:
##################################
# Taking a snapshot of the dataset
##################################
xray_images.head()
Out[20]:
Image_ID Path Diagnosis Target Class Image
0 COVID-1 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19 [[15, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
1 COVID-10 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19 [[129, 125, 123, 121, 119, 117, 114, 104, 104,...
2 COVID-100 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19 [[11, 0, 0, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0...
3 COVID-1000 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19 [[42, 39, 38, 42, 38, 35, 31, 26, 24, 24, 24, ...
4 COVID-1001 C:/Users/John pauline magno/Python Notebooks/C... COVID 0 Covid-19 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 0,...
In [21]:
##################################
# Taking a snapshot of the dataset
##################################
n_samples = 5
fig, m_axs = plt.subplots(3, n_samples, figsize = (3*n_samples, 8))
for n_axs, (type_name, type_rows) in zip(m_axs, xray_images.sort_values(['Diagnosis']).groupby('Diagnosis')):
    n_axs[2].set_title(type_name, fontsize = 14, weight = 'bold')
    for c_ax, (_, c_row) in zip(n_axs, type_rows.sample(n_samples, random_state=1).iterrows()):       
        picture = c_row['Path']
        image = cv2.imread(picture)
        c_ax.imshow(image)
        c_ax.axis('off')
In [22]:
##################################
# Sampling a single image
##################################
samples, features = xray_images.shape
plt.figure()
pic_id = random.randrange(0, samples)
picture = xray_images['Path'][pic_id]
image = cv2.imread(picture) 
<Figure size 640x480 with 0 Axes>
In [23]:
##################################
# Plotting using subplots
##################################
plt.figure(figsize=(15, 5))

##################################
# Formulating the original image
##################################
plt.subplot(1, 4, 1)
plt.imshow(image)
plt.title('Original Image', fontsize = 14, weight = 'bold')
plt.axis('off')

##################################
# Formulating the blue channel
##################################
plt.subplot(1, 4, 2)
plt.imshow(image[ : , : , 0])
plt.title('Blue Channel', fontsize = 14, weight = 'bold')
plt.axis('off')

##################################
# Formulating the green channel
##################################
plt.subplot(1, 4, 3)
plt.imshow(image[ : , : , 1])
plt.title('Green Channel', fontsize = 14, weight = 'bold')
plt.axis('off')

##################################
# Formulating the red channel
##################################
plt.subplot(1, 4, 4)
plt.imshow(image[ : , : , 2])
plt.title('Red Channel', fontsize = 14, weight = 'bold')
plt.axis('off')

##################################
# Consolidating all images
##################################
plt.show()
In [24]:
##################################
# Determining the image shape
##################################
print('Image Shape:')
display(image.shape)
Image Shape:
(299, 299, 3)
In [25]:
##################################
# Determining the image height
##################################
print('Image Height:')
display(image.shape[0])
Image Height:
299
In [26]:
##################################
# Determining the image width
##################################
print('Image Width:')
display(image.shape[0])
Image Width:
299
In [27]:
##################################
# Determining the image dimension
##################################
print('Image Dimension:')
display(image.ndim)
Image Dimension:
3
In [28]:
##################################
# Determining the image size
##################################
print('Image Size:')
display(image.size)
Image Size:
268203
In [29]:
##################################
# Determining the image data type
##################################
print('Image Data Type:')
display(image.dtype)
Image Data Type:
dtype('uint8')
In [30]:
##################################
# Determining the maximum RGB value
##################################
print('Image Maximum RGB:')
display(image.max())
Image Maximum RGB:
205
In [31]:
##################################
# Determining the minimum RGB value
##################################
print('Image Minimum RGB:')
display(image.min())
Image Minimum RGB:
10

1.4.2 Image Augmentation ¶

  1. Different image augmentation techniques were applied using various transformations to the training images to artificially increase the diversity of the dataset and improve the generalization and robustness of the model, including:
    • 1.1 Rescaling - normalization of the pixel values within the 0 to 1 range
    • 1.2 Rotation - random image rotation by 20 degrees
    • 1.3 Width Shift - random horizontal shifting of the image by 20% of the total width
    • 1.4 Height Shift - random vertical shifting of the image by 20% of the total height
    • 1.5 Horizontal Flip - random horizontal flipping of the image
    • 1.6 Vertical Flip - random vertical flipping of the image
    • 1.7 Shear Transformation - image slanting by 20 degrees along the horizontal axis.
    • 1.8 Zooming - random image zoom-in or zoom-out by a factor of 20%
In [32]:
##################################
# Identifying the path for the images
# and defining image categories 
##################################
path = 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset'
classes=["COVID", "Normal", "Viral Pneumonia"]
num_classes = len(classes)
batch_size = 16
In [33]:
##################################
# Creating subsets of images
# for model training and
# setting the parameters for
# real-time data augmentation
# at each epoch
##################################
set_seed()
train_datagen = ImageDataGenerator(rescale=1./255,
                                   rotation_range=20,
                                   width_shift_range=0.2,
                                   height_shift_range=0.2,
                                   horizontal_flip=True,
                                   vertical_flip=True,
                                   shear_range=0.2,
                                   zoom_range=0.2,
                                   validation_split=0.2)


##################################
# Loading the model training images
##################################
train_gen = train_datagen.flow_from_directory(directory=path, 
                                              target_size=(299, 299),
                                              class_mode='categorical',
                                              subset='training',
                                              shuffle=True, 
                                              classes=classes,
                                              batch_size=batch_size, 
                                              color_mode="grayscale")
Found 2880 images belonging to 3 classes.
In [34]:
##################################
# Loading samples of augmented images
# for the training set
##################################
fig, axes = plt.subplots(1, 5, figsize=(15, 3))

for i in range(5):
    batch = next(train_gen)
    images, labels = batch
    axes[i].imshow(images[0])  # Display the first image in the batch
    axes[i].set_title(f"Label: {labels[0]}")
    axes[i].axis('off')
plt.show()
In [35]:
##################################
# Creating subsets of images
# for model validation
# setting the parameters for
# real-time data augmentation
# at each epoch
##################################
set_seed()
test_datagen = ImageDataGenerator(rescale=1./255, 
                                  validation_split=0.2)

##################################
# Loading the model evaluation images
##################################
test_gen = test_datagen.flow_from_directory(directory=path, 
                                            target_size=(299, 299),
                                            class_mode='categorical',
                                            subset='validation',
                                            shuffle=False, 
                                            classes=classes,
                                            batch_size=batch_size, 
                                            color_mode="grayscale")
Found 720 images belonging to 3 classes.
In [36]:
##################################
# Loading samples of augmented images
# for the validation set
##################################
fig, axes = plt.subplots(1, 5, figsize=(15, 3))

for i in range(5):
    batch = next(test_gen)
    images, labels = batch
    axes[i].imshow(images[0])
    axes[i].set_title(f"Label: {labels[0]}")
    axes[i].axis('off')
plt.show()

1.5. Data Exploration ¶

1.5.1 Exploratory Data Analysis ¶

  1. Distinct patterns were observed between the image categories.
    • 1.1 Images identified with CLASS: COVID had the following characteristics:
      • 1.1.1 Higher mean pixel values indicating generally lighter images
      • 1.1.2 Bimodal and wider distribution of maximum pixel values indicating a higher variation in highest possible values
      • 1.1.3 Wider range of image pixel standard deviation indicating a higher variation in contrast
    • 1.2 Images identified with CLASS: Viral Pneumonia had the following characteristics:
      • 1.2.1 Higher mean pixel values indicating generally lighter images
      • 1.2.2 Bimodal and wider distribution of maximum pixel values indicating a higher variation in highest possible values
      • 1.2.3 Wider range of image pixel standard deviation indicating a higher variation in contrast
    • 1.3 Images identified with CLASS: Normal had the following characteristics:
      • 1.3.1 Lower mean pixel values indicating generally darker images
      • 1.3.2 Unimodal and steeper distribution of maximum pixel values indicating more stable highest possible values
      • 1.3.3 Compact range of image pixel standard deviation indicating images with stable and sufficient contrast
In [37]:
##################################
# Consolidating summary statistics
# for the image pixel values
##################################
mean_val = []
std_dev_val = []
max_val = []
min_val = []

for i in range(0, samples):
    mean_val.append(xray_images['Image'][i].mean())
    std_dev_val.append(np.std(xray_images['Image'][i]))
    max_val.append(xray_images['Image'][i].max())
    min_val.append(xray_images['Image'][i].min())

imageEDA = xray_images.loc[:,['Image', 'Class','Path']]
imageEDA['Mean'] = mean_val
imageEDA['StDev'] = std_dev_val
imageEDA['Max'] = max_val
imageEDA['Min'] = min_val
In [38]:
##################################
# Formulating the mean distribution
# by category of the image pixel values
##################################
sns.displot(data = imageEDA, x = 'Mean', kind="kde", hue = 'Class', height=6, aspect=1.40)
plt.title('Image Pixel Mean Distribution by Category', fontsize=14, weight='bold');
In [39]:
##################################
# Formulating the maximum distribution
# by category of the image pixel values
##################################
sns.displot(data = imageEDA, x = 'Max', kind="kde", hue = 'Class', height=6, aspect=1.40)
plt.title('Image Pixel Maximum Distribution by Category', fontsize=14, weight='bold');
In [40]:
##################################
# Formulating the minimum distribution
# by category of the image pixel values
##################################
sns.displot(data = imageEDA, x = 'Min', kind="kde", hue = 'Class', height=6, aspect=1.40)
plt.title('Image Pixel Minimum Distribution by Category', fontsize=14, weight='bold');
In [41]:
##################################
# Formulating the standard deviation distribution
# by category of the image pixel values
##################################
sns.displot(data = imageEDA, x = 'StDev', kind="kde", hue = 'Class', height=6, aspect=1.40)
plt.title('Image Pixel Standard Deviation Distribution by Category', fontsize=14, weight='bold');
In [42]:
##################################
# Formulating the mean and standard deviation 
# scatterplot distribution
# by category of the image pixel values
##################################
plt.figure(figsize=(10,6))
sns.set(style="ticks", font_scale = 1)
ax = sns.scatterplot(data=imageEDA, x="Mean", y=imageEDA['StDev'], hue='Class', alpha=0.5)
sns.despine(top=True, right=True, left=False, bottom=False)
plt.xticks(rotation=0, fontsize = 12)
ax.set_xlabel('Image Pixel Mean',fontsize=14, weight='bold')
ax.set_ylabel('Image Pixel Standard Deviation', fontsize=14, weight='bold')
plt.title('Image Pixel Mean and Standard Deviation Distribution', fontsize = 14, weight='bold');
In [43]:
##################################
# Formulating the mean and standard deviation 
# scatterplot distribution
# by category of the image pixel values
##################################
scatterplot = sns.FacetGrid(imageEDA, col="Class", height=6)
scatterplot.map_dataframe(sns.scatterplot, x='Mean', y='StDev', alpha=0.5)
scatterplot.set_titles(col_template="{col_name}", row_template="{row_name}", size=18)
scatterplot.fig.subplots_adjust(top=.8)
scatterplot.fig.suptitle('Image Pixel Mean and Standard Deviation Distribution', fontsize=14, weight='bold')
axes = scatterplot.axes.flatten()
axes[0].set_ylabel('Image Pixel Standard Deviation')
for ax in axes:
    ax.set_xlabel('Image Pixel Mean')
scatterplot.fig.tight_layout()
In [44]:
##################################
# Formulating the mean and standard deviation 
# scatterplot distribution
# of the image pixel values
# represented as actual images
##################################
def getImage(path):
    return OffsetImage(cv2.imread(path),zoom = 0.1)

DF_sample = imageEDA.sample(frac=1.0, replace=False, random_state=1)
paths = DF_sample['Path']

fig, ax = plt.subplots(figsize=(15,9))
ab = sns.scatterplot(data=DF_sample, x="Mean", y='StDev')
sns.despine(top=True, right=True, left=False, bottom=False)
ax.set_xlabel('Image Pixel Mean', fontsize=14, weight='bold')
ax.set_ylabel('Image Pixel Standard Deviation', fontsize=14, weight='bold')
ax.set_xlim(40,220)
ax.set_ylim(10,110)
plt.title('Overall: Image Pixel Mean and Standard Deviation Distribution', fontsize=14, weight='bold');

for x0, y0, path in zip(DF_sample['Mean'], DF_sample['StDev'],paths):
    ab = AnnotationBbox(getImage(path), (x0, y0), frameon=False)
    ax.add_artist(ab)
In [45]:
##################################
# Formulating the mean and standard deviation 
# scatterplot distribution
# of the image pixel values
# represented as actual images
# for the Covid-19 class
##################################
path_covid = 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset/COVID/'
imageEDA_covid = imageEDA.loc[imageEDA['Class'] == 'Covid-19']

def getImage(path_covid):
    return OffsetImage(cv2.imread(path_covid),zoom = 0.1)

DF_sample = imageEDA_covid.sample(frac=1.0, replace=False, random_state=1)
paths = DF_sample['Path']

fig, ax = plt.subplots(figsize=(15,9))
ab = sns.scatterplot(data=DF_sample, x="Mean", y='StDev')
sns.despine(top=True, right=True, left=False, bottom=False)
ax.set_xlabel('Image Pixel Mean', fontsize=14, weight='bold')
ax.set_ylabel('Image Pixel Standard Deviation', fontsize=14, weight='bold')
ax.set_xlim(40,220)
ax.set_ylim(10,110)
plt.title('Covid-19: Image Pixel Mean and Standard Deviation Distribution', fontsize=14, weight='bold');

for x0, y0, path_covid in zip(DF_sample['Mean'], DF_sample['StDev'],paths):
    ab = AnnotationBbox(getImage(path_covid), (x0, y0), frameon=False)
    ax.add_artist(ab)
In [46]:
##################################
# Formulating the mean and standard deviation 
# scatterplot distribution
# of the image pixel values
# represented as actual images
# for the Viral Pneumonia class
##################################
path_viral_pneumonia = 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset/Viral Pneumonia/'
imageEDA_viral_pneumonia = imageEDA.loc[imageEDA['Class'] == 'Viral Pneumonia']

def getImage(path_viral_pneumonia):
    return OffsetImage(cv2.imread(path_viral_pneumonia),zoom = 0.1)

DF_sample = imageEDA_viral_pneumonia.sample(frac=1.0, replace=False, random_state=1)
paths = DF_sample['Path']

fig, ax = plt.subplots(figsize=(15,9))
ab = sns.scatterplot(data=DF_sample, x="Mean", y='StDev')
sns.despine(top=True, right=True, left=False, bottom=False)
ax.set_xlabel('Image Pixel Mean', fontsize=14, weight='bold')
ax.set_ylabel('Image Pixel Standard Deviation', fontsize=14, weight='bold')
ax.set_xlim(40,220)
ax.set_ylim(10,110)
plt.title('Viral Pneumonia: Image Pixel Mean and Standard Deviation Distribution', fontsize=14, weight='bold');

for x0, y0, path_viral_pneumonia in zip(DF_sample['Mean'], DF_sample['StDev'],paths):
    ab = AnnotationBbox(getImage(path_viral_pneumonia), (x0, y0), frameon=False)
    ax.add_artist(ab)
In [47]:
##################################
# Formulating the mean and standard deviation 
# scatterplot distribution
# of the image pixel values
# represented as actual images
# for the Viral Pneumonia class
##################################
path_normal = 'C:/Users/John pauline magno/Python Notebooks/COVID-19_Radiography_Dataset/Normal/'
imageEDA_normal = imageEDA.loc[imageEDA['Class'] == 'Healthy']

def getImage(path_normal):
    return OffsetImage(cv2.imread(path_normal),zoom = 0.1)

DF_sample = imageEDA_normal.sample(frac=1.0, replace=False, random_state=1)
paths = DF_sample['Path']

fig, ax = plt.subplots(figsize=(15,9))
ab = sns.scatterplot(data=DF_sample, x="Mean", y='StDev')
sns.despine(top=True, right=True, left=False, bottom=False)
ax.set_xlabel('Image Pixel Mean', fontsize=14, weight='bold')
ax.set_ylabel('Image Pixel Standard Deviation', fontsize=14, weight='bold')
ax.set_xlim(40,220)
ax.set_ylim(10,110)
plt.title('Healthy: Image Pixel Mean and Standard Deviation Distribution', fontsize=14, weight='bold');

for x0, y0, path_normal in zip(DF_sample['Mean'], DF_sample['StDev'],paths):
    ab = AnnotationBbox(getImage(path_normal), (x0, y0), frameon=False)
    ax.add_artist(ab)

1.6. Model Development ¶

1.6.1 Premodelling Data Description ¶

  1. Training data included 2880 augmented images representing 80% of the dataset.
  2. Validation data included 720 non-augmented images representing 20% of the dataset.
  3. Candidate models were formulated using common layers as follows:
    • 3.1 Convolutional Layer - extracts features from input images using convolutional filters
    • 3.2 Maximum Pooling Layer - Reduces spatial dimensions and downsamples feature maps
    • 3.3 Activation Layer - Applies an activation function element-wise to the output
    • 3.4 Flatten Layer - Flattens the input to a 1D array, preparing for fully connected layers
    • 3.5 Dense Layer - Fully connected layer for classification
  4. Different iterations of the model were formulated using variations in the inclusion or exclusion of the following regularization layers:
    • 4.1 Dropout Layer - randomly drops (sets to zero) a fraction of the neurons during training reducing co-dependencies between them
    • 4.2 Batch Normalization Layer - adjusts and scales the inputs to a layer reducing the sensitivity to weight initialization choices
  5. A subset of hyperparameters for the different layers were fixed during model training including:
    • 5.1 Filters - setting used to capture spatial hierarchies and features in the input images
    • 5.2 Kernel Size - setting used to define the local region the convolutional layer considers when processing the input
    • 5.3 Activation - setting used to introduce non-linearity into the model, enabling it to learn complex relationships in the data
    • 5.4 Pool Size - setting used to reduce the spatial dimensions of the feature maps to focus on the most important features
    • 5.5 Padding - setting used to control the spatial size and shape for every convolutional operation at each stage
    • 5.6 Dense Units - setting used to process the flattened feature maps and determine the dimensionality of the output space
    • 5.7 Optimizer - setting used to determine how the model's weights are updated during training
    • 5.8 Learning Rate - setting used to determine the step size at each iteration during optimization
    • 5.9 Batch Size - setting used to determine how many samples are used in each iteration of training
    • 5.10 Loss - setting used to define the objective that the model seeks to minimize during training

1.6.2 CNN With No Regularization ¶

  1. The convolutional neural network model from the keras.models Python library API was implemented.
  2. The model contains 7 layers with fixed hyperparameters as follows:
    • Conv2D: conv2d
      • filters = 32
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
      • input_shape = 299x299x1
    • MaxPooling2D: max_pooling2d
      • pool_size = 2x2
    • Conv2D: conv2d_1
      • filters = 64
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
    • MaxPooling2D: max_pooling2d_1
      • pool_size = 2x2
    • Flatten: flatten
    • Dense: dense
      • units = 128
      • activation = relu (rectified linear unit)
    • Dense: dense_1
      • units = 3
      • activation = softmax
  3. Additional fixed hyperparameters used during model compilation are as follows:
    • loss = categorical_crossentropy
    • optimizer = adam (adaptive moment estimation)
    • metrics = recall
  4. The model contained 44,878,723 trainable parameters broken down per layer as follows:
    • Conv2D: conv2d
      • output size = 299x299x32
      • number of parameters = 320
    • MaxPooling2D: max_pooling2d
      • output size = 149x149x32
      • number of parameters = 0
    • Conv2D: conv2d_1
      • output size = 149x149x64
      • number of parameters = 18496
    • MaxPooling2D: max_pooling2d_1
      • output size = 74x74x64
      • number of parameters = 0
    • Flatten: flatten
      • output size = 350464
      • number of parameters = 0
    • Dense: dense
      • output size = 128
      • number of parameters = 44859520
    • Dense: dense_1
      • output size = 3
      • number of parameters = 387
  5. The model performance on the validation set for all image categories is summarized as follows:
    • Precision = 0.7906
    • Recall = 0.7819
    • F1 Score = 0.7825
In [48]:
##################################
# Defining a function for
# plotting the loss profile
# of the training and validation sets
#################################
def plot_training_history(history, model_name):
    plt.figure(figsize=(10,6))
    plt.plot(history.history['loss'], label='Train')
    plt.plot(history.history['val_loss'], label='Validation')
    plt.title(f'{model_name} Training Loss', fontsize = 16, weight = 'bold', pad=20)
    plt.ylim(0, 5)
    plt.xlabel('Epoch', fontsize = 14, weight = 'bold',)
    plt.ylabel('Loss', fontsize = 14, weight = 'bold',)
    plt.legend()
    plt.show()
In [49]:
##################################
# Formulating the network architecture
# for CNN with no regularization
##################################
set_seed()
batch_size = 16
model_nr = Sequential()
model_nr.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='Same', input_shape=(299, 299, 1)))
model_nr.add(MaxPooling2D(pool_size=(2, 2)))
model_nr.add(Conv2D(filters=64, kernel_size=(3, 3), padding='Same', activation='relu'))
model_nr.add(MaxPooling2D(pool_size=(2, 2)))
model_nr.add(Flatten())
model_nr.add(Dense(units=128, activation='relu'))
model_nr.add(Dense(units=num_classes, activation='softmax'))

##################################
# Compiling the network layers
##################################
model_nr.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[Recall()])
WARNING:tensorflow:From C:\Users\John pauline magno\AppData\Roaming\Python\Python311\site-packages\keras\backend.py:873: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.

WARNING:tensorflow:From C:\Users\John pauline magno\AppData\Roaming\Python\Python311\site-packages\keras\layers\pooling\max_pooling2d.py:160: The name tf.nn.max_pool is deprecated. Please use tf.nn.max_pool2d instead.

WARNING:tensorflow:From C:\Users\John pauline magno\AppData\Roaming\Python\Python311\site-packages\keras\optimizers\__init__.py:300: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.

In [50]:
##################################
# Displaying the model summary
# for CNN with no regularization
##################################
print(model_nr.summary())
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 299, 299, 32)      320       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 149, 149, 32)     0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (None, 149, 149, 64)      18496     
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 74, 74, 64)       0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (None, 350464)            0         
                                                                 
 dense (Dense)               (None, 128)               44859520  
                                                                 
 dense_1 (Dense)             (None, 3)                 387       
                                                                 
=================================================================
Total params: 44,878,723
Trainable params: 44,878,723
Non-trainable params: 0
_________________________________________________________________
None
In [51]:
##################################
# Displaying the model layers
# for CNN with no regularization
##################################
model_nr_layer_names = [layer.name for layer in model_nr.layers]
print("Layer Names:", model_nr_layer_names)
Layer Names: ['conv2d', 'max_pooling2d', 'conv2d_1', 'max_pooling2d_1', 'flatten', 'dense', 'dense_1']
In [52]:
##################################
# Displaying the number of weights
# for each model layer
# for CNN with no regularization
##################################
for layer in model_nr.layers:
    if hasattr(layer, 'weights'):
        print(f"Layer: {layer.name}, Number of Weights: {len(layer.get_weights())}")
Layer: conv2d, Number of Weights: 2
Layer: max_pooling2d, Number of Weights: 0
Layer: conv2d_1, Number of Weights: 2
Layer: max_pooling2d_1, Number of Weights: 0
Layer: flatten, Number of Weights: 0
Layer: dense, Number of Weights: 2
Layer: dense_1, Number of Weights: 2
In [53]:
##################################
# Displaying the number of weights
# for each model layer
# for CNN with no regularization
##################################
total_parameters = 0
for layer in model_nr.layers:
    layer_parameters = layer.count_params()
    total_parameters += layer_parameters
    print(f"Layer: {layer.name}, Parameters: {layer_parameters}")
print("\nTotal Parameters in the Model:", total_parameters)
Layer: conv2d, Parameters: 320
Layer: max_pooling2d, Parameters: 0
Layer: conv2d_1, Parameters: 18496
Layer: max_pooling2d_1, Parameters: 0
Layer: flatten, Parameters: 0
Layer: dense, Parameters: 44859520
Layer: dense_1, Parameters: 387

Total Parameters in the Model: 44878723
In [54]:
##################################
# Fitting the model
# for CNN with no regularization
##################################
epochs = 100
set_seed()
model_nr_history = model_nr.fit(train_gen, 
                                steps_per_epoch=len(train_gen) // batch_size,   
                                validation_steps=len(test_gen) // batch_size, 
                                validation_data=test_gen, 
                                epochs=epochs,
                                verbose=0)
WARNING:tensorflow:From C:\Users\John pauline magno\AppData\Roaming\Python\Python311\site-packages\keras\utils\tf_utils.py:490: The name tf.ragged.RaggedTensorValue is deprecated. Please use tf.compat.v1.ragged.RaggedTensorValue instead.

In [55]:
##################################
# Evaluating the model
# for CNN with no regularization
# on the independent validation set
##################################
model_nr_y_pred = model_nr.predict(test_gen)
45/45 [==============================] - 4s 80ms/step
In [56]:
##################################
# Plotting the loss profile
# for CNN with no regularization
# on the training and validation sets
##################################
plot_training_history(model_nr_history, 'CNN With No Regularization : ')
In [57]:
##################################
# Consolidating the predictions
# for CNN with no regularization
# on the validation set
##################################
model_nr_predictions = np.array(list(map(lambda x: np.argmax(x), model_nr_y_pred)))
model_nr_y_true = test_gen.classes

##################################
# Formulating the confusion matrix
# for CNN with no regularization
# on the validation set
##################################
CMatrix = pd.DataFrame(confusion_matrix(model_nr_y_true, model_nr_predictions), columns=classes, index =classes)

##################################
# Plotting the confusion matrix
# for CNN with no regularization
# on the validation set
##################################
plt.figure(figsize=(10, 6))
ax = sns.heatmap(CMatrix, annot = True, fmt = 'g' ,vmin = 0, vmax = 250,cmap = 'icefire')
ax.set_xlabel('Predicted',fontsize = 14,weight = 'bold')
ax.set_xticklabels(ax.get_xticklabels(),rotation =0)
ax.set_ylabel('Actual',fontsize = 14,weight = 'bold') 
ax.set_yticklabels(ax.get_yticklabels(),rotation =0)
ax.set_title('CNN With No Regularization : Validation Set Confusion Matrix',fontsize = 14, weight = 'bold',pad=20);

##################################
# Resetting all states generated by Keras
##################################
keras.backend.clear_session()
In [58]:
##################################
# Calculating the model accuracy
# for CNN with no regularization
# for the entire validation set
##################################
model_nr_acc = accuracy_score(model_nr_y_true, model_nr_predictions)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with no regularization
# for the entire validation set
##################################
model_nr_results_all = precision_recall_fscore_support(model_nr_y_true, model_nr_predictions, average='macro',zero_division = 1)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with no regularization
# for each category of the validation set
##################################
model_nr_results_class = precision_recall_fscore_support(model_nr_y_true, model_nr_predictions, average=None, zero_division = 1)

##################################
# Consolidating all model evaluation metrics 
# for CNN with no regularization
##################################
metric_columns = ['Precision','Recall','F-Score','Support']
model_nr_all_df = pd.concat([pd.DataFrame(list(model_nr_results_class)).T,pd.DataFrame(list(model_nr_results_all)).T])
model_nr_all_df.columns = metric_columns
model_nr_all_df.index = ['COVID', 'Normal', 'Viral Pneumonia','Total']
model_nr_all_df
Out[58]:
Precision Recall F-Score Support
COVID 0.890295 0.879167 0.884696 240.0
Normal 0.671378 0.791667 0.726577 240.0
Viral Pneumonia 0.810000 0.675000 0.736364 240.0
Total 0.790558 0.781944 0.782546 NaN
In [59]:
##################################
# Consolidating all model evaluation metrics 
# for CNN with no regularization
##################################
model_nr_model_list = []
model_nr_measure_list = []
model_nr_category_list = []
model_nr_value_list = []

for i in range(3): 
    for j in range(4):
        model_nr_model_list.append('CNN_NR')
        model_nr_measure_list.append(metric_columns[i])
        model_nr_category_list.append(model_nr_all_df.index[j])
        model_nr_value_list.append(model_nr_all_df.iloc[j,i])

model_nr_all_summary = pd.DataFrame(zip(model_nr_model_list,
                                        model_nr_measure_list,
                                        model_nr_category_list,
                                        model_nr_value_list), 
                                        columns=['CNN.Model.Name',
                                                 'Model.Metric',
                                                 'Image.Category',
                                                 'Metric.Value'])

1.6.3 CNN With Dropout Regularization ¶

  1. The convolutional neural network model from the keras.models Python library API was implemented.
  2. The model contains 8 layers with fixed hyperparameters as follows:
    • Conv2D: conv2d
      • filters = 32
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
      • input_shape = 299x299x1
    • MaxPooling2D: max_pooling2d
      • pool_size = 2x2
    • Conv2D: conv2d_1
      • filters = 64
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
    • Dropout: dropout
      • rate = 0.25
    • MaxPooling2D: max_pooling2d_1
      • pool_size = 2x2
    • Flatten: flatten
    • Dense: dense
      • units = 128
      • activation = relu (rectified linear unit)
    • Dense: dense_1
      • units = 3
      • activation = softmax
  3. Additional fixed hyperparameters used during model compilation are as follows:
    • loss = categorical_crossentropy
    • optimizer = adam (adaptive moment estimation)
    • metrics = recall
  4. The model contained 44,878,723 trainable parameters broken down per layer as follows:
    • Conv2D: conv2d
      • output size = 299x299x32
      • number of parameters = 320
    • MaxPooling2D: max_pooling2d
      • output size = 149x149x32
      • number of parameters = 0
    • Dropout: dropout
      • output size = 149x149x64
      • number of parameters = 0
    • Conv2D: conv2d_1
      • output size = 149x149x64
      • number of parameters = 18496
    • MaxPooling2D: max_pooling2d_1
      • output size = 74x74x64
      • number of parameters = 0
    • Flatten: flatten
      • output size = 350464
      • number of parameters = 0
    • Dense: dense
      • output size = 128
      • number of parameters = 44859520
    • Dense: dense_1
      • output size = 3
      • number of parameters = 387
  5. The model performance on the validation set for all image categories is summarized as follows:
    • Precision = 0.8565
    • Recall = 0.8472
    • F1 Score = 0.8457
In [60]:
##################################
# Formulating the network architecture
# for CNN with dropout regularization
##################################
set_seed()
batch_size = 16
model_dr = Sequential()
model_dr.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='Same', input_shape=(299, 299, 1)))
model_dr.add(MaxPooling2D(pool_size=(2, 2)))
model_dr.add(Conv2D(filters=64, kernel_size=(3, 3), padding = 'Same', activation='relu'))
model_dr.add(Dropout(rate=0.25))
model_dr.add(MaxPooling2D(pool_size=(2, 2)))
model_dr.add(Flatten())
model_dr.add(Dense(units=128, activation='relu'))
model_dr.add(Dense(units=num_classes, activation='softmax'))

##################################
# Compiling the network layers
##################################
model_dr.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[Recall()])
In [61]:
##################################
# Displaying the model summary
# for CNN with dropout regularization
##################################
print(model_dr.summary())
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 299, 299, 32)      320       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 149, 149, 32)     0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (None, 149, 149, 64)      18496     
                                                                 
 dropout (Dropout)           (None, 149, 149, 64)      0         
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 74, 74, 64)       0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (None, 350464)            0         
                                                                 
 dense (Dense)               (None, 128)               44859520  
                                                                 
 dense_1 (Dense)             (None, 3)                 387       
                                                                 
=================================================================
Total params: 44,878,723
Trainable params: 44,878,723
Non-trainable params: 0
_________________________________________________________________
None
In [62]:
##################################
# Displaying the model layers
# for CNN with dropout regularization
##################################
model_dr_layer_names = [layer.name for layer in model_dr.layers]
print("Layer Names:", model_dr_layer_names)
Layer Names: ['conv2d', 'max_pooling2d', 'conv2d_1', 'dropout', 'max_pooling2d_1', 'flatten', 'dense', 'dense_1']
In [63]:
##################################
# Displaying the number of weights
# for each model layer
# for CNN with dropout regularization
##################################
for layer in model_dr.layers:
    if hasattr(layer, 'weights'):
        print(f"Layer: {layer.name}, Number of Weights: {len(layer.get_weights())}")
Layer: conv2d, Number of Weights: 2
Layer: max_pooling2d, Number of Weights: 0
Layer: conv2d_1, Number of Weights: 2
Layer: dropout, Number of Weights: 0
Layer: max_pooling2d_1, Number of Weights: 0
Layer: flatten, Number of Weights: 0
Layer: dense, Number of Weights: 2
Layer: dense_1, Number of Weights: 2
In [64]:
##################################
# Displaying the number of weights
# for each model layer
# for CNN with dropout regularization
##################################
total_parameters = 0
for layer in model_dr.layers:
    layer_parameters = layer.count_params()
    total_parameters += layer_parameters
    print(f"Layer: {layer.name}, Parameters: {layer_parameters}")
print("\nTotal Parameters in the Model:", total_parameters)
Layer: conv2d, Parameters: 320
Layer: max_pooling2d, Parameters: 0
Layer: conv2d_1, Parameters: 18496
Layer: dropout, Parameters: 0
Layer: max_pooling2d_1, Parameters: 0
Layer: flatten, Parameters: 0
Layer: dense, Parameters: 44859520
Layer: dense_1, Parameters: 387

Total Parameters in the Model: 44878723
In [65]:
##################################
# Fitting the model
# for CNN with dropout regularization
##################################
epochs = 100
set_seed()
model_dr_history = model_dr.fit(train_gen, 
                                steps_per_epoch=len(train_gen) // batch_size, 
                                validation_steps=len(test_gen) // batch_size, 
                                validation_data=test_gen, 
                                epochs=epochs,
                                verbose=0)
In [66]:
##################################
# Evaluating the model
# for CNN with dropout regularization
# on the independent validation set
##################################
model_dr_y_pred = model_dr.predict(test_gen)
45/45 [==============================] - 4s 79ms/step
In [67]:
##################################
# Plotting the loss profile
# for CNN with dropout regularization
# on the training and validation sets
##################################
plot_training_history(model_dr_history, 'CNN With Dropout Regularization : ')
In [68]:
##################################
# Consolidating the predictions
# for CNN with dropout regularization
# on the validation set
##################################
model_dr_predictions = np.array(list(map(lambda x: np.argmax(x), model_dr_y_pred)))
model_dr_y_true=test_gen.classes

##################################
# Formulating the confusion matrix
# for CNN with dropout regularization
# on the validation set
##################################
CMatrix = pd.DataFrame(confusion_matrix(model_dr_y_true, model_dr_predictions), columns=classes, index =classes)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with dropout regularization
# for each category of the validation set
##################################
plt.figure(figsize=(10, 6))
ax = sns.heatmap(CMatrix, annot = True, fmt = 'g' ,vmin = 0, vmax = 250, cmap = 'icefire')
ax.set_xlabel('Predicted',fontsize = 14,weight = 'bold')
ax.set_xticklabels(ax.get_xticklabels(),rotation =0)
ax.set_ylabel('Actual',fontsize = 14,weight = 'bold') 
ax.set_yticklabels(ax.get_yticklabels(),rotation =0)
ax.set_title('CNN With Dropout Regularization : Validation Set Confusion Matrix',fontsize = 14, weight = 'bold', pad=20);

##################################
# Resetting all states generated by Keras
##################################
keras.backend.clear_session()
In [69]:
##################################
# Calculating the model accuracy
# for CNN with dropout regularization
# for the entire validation set
##################################
model_dr_acc = accuracy_score(model_dr_y_true, model_dr_predictions)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with dropout regularization
# for the entire validation set
##################################
model_dr_results_all = precision_recall_fscore_support(model_dr_y_true, model_dr_predictions, average='macro',zero_division = 1)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with dropout regularization
# for each category of the validation set
##################################
model_dr_results_class = precision_recall_fscore_support(model_dr_y_true, model_dr_predictions, average=None, zero_division = 1)

##################################
# Consolidating all model evaluation metrics 
# for CNN with dropout regularization
##################################
metric_columns = ['Precision','Recall', 'F-Score','Support']
model_dr_all_df = pd.concat([pd.DataFrame(list(model_dr_results_class)).T,pd.DataFrame(list(model_dr_results_all)).T])
model_dr_all_df.columns = metric_columns
model_dr_all_df.index = ['COVID', 'Normal', 'Viral Pneumonia','Total']
model_dr_all_df
Out[69]:
Precision Recall F-Score Support
COVID 0.906504 0.929167 0.917695 240.0
Normal 0.904255 0.708333 0.794393 240.0
Viral Pneumonia 0.758741 0.904167 0.825095 240.0
Total 0.856500 0.847222 0.845728 NaN
In [70]:
##################################
# Consolidating all model evaluation metrics 
# for CNN with dropout regularization
##################################
model_dr_model_list = []
model_dr_measure_list = []
model_dr_category_list = []
model_dr_value_list = []

for i in range(3): 
    for j in range(4):
        model_dr_model_list.append('CNN_DR')
        model_dr_measure_list.append(metric_columns[i])
        model_dr_category_list.append(model_dr_all_df.index[j])
        model_dr_value_list.append(model_dr_all_df.iloc[j,i])

model_dr_all_summary = pd.DataFrame(zip(model_dr_model_list,
                                        model_dr_measure_list,
                                        model_dr_category_list,
                                        model_dr_value_list), 
                                        columns=['CNN.Model.Name',
                                                 'Model.Metric',
                                                 'Image.Category',
                                                 'Metric.Value'])

1.6.4 CNN With Batch Normalization Regularization ¶

  1. The convolutional neural network model from the keras.models Python library API was implemented.
  2. The model contains 9 layers with fixed hyperparameters as follows:
    • Conv2D: conv2d
      • filters = 32
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
      • input_shape = 299x299x1
    • MaxPooling2D: max_pooling2d
      • pool_size = 2x2
    • Conv2D: conv2d_1
      • filters = 64
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
    • BatchNormalization: batch_normalization
    • Activation: activation
      • activation = relu (rectified linear unit)
    • MaxPooling2D: max_pooling2d_1
      • pool_size = 2x2
    • Flatten: flatten
    • Dense: dense
      • units = 128
      • activation = relu (rectified linear unit)
    • Dense: dense_1
      • units = 3
      • activation = softmax
  3. Additional fixed hyperparameters used during model compilation are as follows:
    • loss = categorical_crossentropy
    • optimizer = adam (adaptive moment estimation)
    • metrics = recall
  4. The model contained 44,878,979 trainable parameters broken down per layer as follows:
    • Conv2D: conv2d
      • output size = 299x299x32
      • number of parameters = 320
    • MaxPooling2D: max_pooling2d
      • output size = 149x149x32
      • number of parameters = 0
    • BatchNormalization: batch_normalization
      • output size = 149x149x64
      • number of parameters = 256
    • Activation: activation
      • output size = 149x149x64
      • number of parameters = 0
    • Conv2D: conv2d_1
      • output size = 149x149x64
      • number of parameters = 18496
    • MaxPooling2D: max_pooling2d_1
      • output size = 74x74x64
      • number of parameters = 0
    • Flatten: flatten
      • output size = 350464
      • number of parameters = 0
    • Dense: dense
      • output size = 128
      • number of parameters = 44859520
    • Dense: dense_1
      • output size = 3
      • number of parameters = 387
  5. The model performance on the validation set for all image categories is summarized as follows:
    • Precision = 0.9111
    • Recall = 0.9097
    • F1 Score = 0.9097
In [71]:
##################################
# Formulating the network architecture
# for CNN with batch normalization regularization
##################################
set_seed()
batch_size = 16
model_bnr = Sequential()
model_bnr.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='Same', input_shape=(299, 299, 1)))
model_bnr.add(MaxPooling2D(pool_size=(2, 2)))
model_bnr.add(Conv2D(filters=64, kernel_size=(3, 3), padding='Same', activation='relu'))
model_bnr.add(BatchNormalization())
model_bnr.add(Activation('relu'))
model_bnr.add(MaxPooling2D(pool_size=(2, 2)))
model_bnr.add(Flatten())
model_bnr.add(Dense(units=128, activation='relu'))
model_bnr.add(Dense(units=num_classes, activation='softmax'))

##################################
# Compiling the network layers
##################################
model_bnr.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[Recall()])
In [72]:
##################################
# Displaying the model summary
# for CNN with batch normalization regularization
##################################
print(model_bnr.summary())
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 299, 299, 32)      320       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 149, 149, 32)     0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (None, 149, 149, 64)      18496     
                                                                 
 batch_normalization (BatchN  (None, 149, 149, 64)     256       
 ormalization)                                                   
                                                                 
 activation (Activation)     (None, 149, 149, 64)      0         
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 74, 74, 64)       0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (None, 350464)            0         
                                                                 
 dense (Dense)               (None, 128)               44859520  
                                                                 
 dense_1 (Dense)             (None, 3)                 387       
                                                                 
=================================================================
Total params: 44,878,979
Trainable params: 44,878,851
Non-trainable params: 128
_________________________________________________________________
None
In [73]:
##################################
# Displaying the model layers
# for CNN with batch normalization regularization
##################################
model_bnr_layer_names = [layer.name for layer in model_bnr.layers]
print("Layer Names:", model_bnr_layer_names)
Layer Names: ['conv2d', 'max_pooling2d', 'conv2d_1', 'batch_normalization', 'activation', 'max_pooling2d_1', 'flatten', 'dense', 'dense_1']
In [74]:
##################################
# Displaying the number of weights
# for each model layer
# for CNN with batch normalization regularization
##################################
for layer in model_bnr.layers:
    if hasattr(layer, 'weights'):
        print(f"Layer: {layer.name}, Number of Weights: {len(layer.get_weights())}")
Layer: conv2d, Number of Weights: 2
Layer: max_pooling2d, Number of Weights: 0
Layer: conv2d_1, Number of Weights: 2
Layer: batch_normalization, Number of Weights: 4
Layer: activation, Number of Weights: 0
Layer: max_pooling2d_1, Number of Weights: 0
Layer: flatten, Number of Weights: 0
Layer: dense, Number of Weights: 2
Layer: dense_1, Number of Weights: 2
In [75]:
##################################
# Displaying the number of weights
# for each model layer
# for CNN with batch normalization regularization
##################################
total_parameters = 0
for layer in model_bnr.layers:
    layer_parameters = layer.count_params()
    total_parameters += layer_parameters
    print(f"Layer: {layer.name}, Parameters: {layer_parameters}")
print("\nTotal Parameters in the Model:", total_parameters)
Layer: conv2d, Parameters: 320
Layer: max_pooling2d, Parameters: 0
Layer: conv2d_1, Parameters: 18496
Layer: batch_normalization, Parameters: 256
Layer: activation, Parameters: 0
Layer: max_pooling2d_1, Parameters: 0
Layer: flatten, Parameters: 0
Layer: dense, Parameters: 44859520
Layer: dense_1, Parameters: 387

Total Parameters in the Model: 44878979
In [76]:
##################################
# Fitting the model
# for CNN with batch normalization regularization
##################################
epochs = 100
set_seed()
model_bnr_history = model_bnr.fit(train_gen, 
                                  steps_per_epoch=len(train_gen) // batch_size,
                                  validation_steps=len(test_gen) // batch_size, 
                                  validation_data=test_gen, epochs=epochs,
                                  verbose=0)
In [77]:
##################################
# Evaluating the model
# for CNN with batch normalization regularization
# on the independent validation set
##################################
model_bnr_y_pred = model_bnr.predict(test_gen)
45/45 [==============================] - 4s 92ms/step
In [78]:
##################################
# Plotting the loss profile
# for CNN with batch normalization regularization
# on the training and validation sets
##################################
plot_training_history(model_bnr_history, 'CNN With Batch Normalization Regularization : ')
In [79]:
##################################
# Consolidating the predictions
# for CNN with batch normalization regularization
# on the validation set
##################################
model_bnr_predictions = np.array(list(map(lambda x: np.argmax(x), model_bnr_y_pred)))
model_bnr_y_true = test_gen.classes

##################################
# Formulating the confusion matrix
# for CNN with batch normalization regularization
# on the validation set
##################################
CMatrix = pd.DataFrame(confusion_matrix(model_bnr_y_true, model_bnr_predictions), columns=classes, index =classes)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with batch normalization regularization
# for each category of the validation set
##################################
plt.figure(figsize=(10, 6))
ax = sns.heatmap(CMatrix, annot = True, fmt = 'g' ,vmin = 0, vmax = 250,cmap = 'icefire')
ax.set_xlabel('Predicted',fontsize = 14,weight = 'bold')
ax.set_xticklabels(ax.get_xticklabels(),rotation =0)
ax.set_ylabel('Actual',fontsize = 14,weight = 'bold') 
ax.set_yticklabels(ax.get_yticklabels(),rotation =0)
ax.set_title('CNN With Batch Normalization Regularization : Validation Set Confusion Matrix',fontsize = 16,weight = 'bold',pad=20);

##################################
# Resetting all states generated by Keras
##################################
keras.backend.clear_session()
In [80]:
##################################
# Calculating the model accuracy
# for CNN with batch normalization regularization
# for the entire validation set
##################################
model_bnr_acc = accuracy_score(model_bnr_y_true, model_bnr_predictions)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with batch normalization regularization
# for the entire validation set
##################################
model_bnr_results_all = precision_recall_fscore_support(model_bnr_y_true, model_bnr_predictions, average='macro',zero_division = 1)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with batch normalization regularization
# for each category of the validation set
##################################
model_bnr_results_class = precision_recall_fscore_support(model_bnr_y_true, model_bnr_predictions, average=None, zero_division = 1)

##################################
# Consolidating all model evaluation metrics 
# for CNN with batch normalization regularization
##################################
metric_columns = ['Precision','Recall', 'F-Score','Support']
model_bnr_all_df = pd.concat([pd.DataFrame(list(model_bnr_results_class)).T,pd.DataFrame(list(model_bnr_results_all)).T])
model_bnr_all_df.columns = metric_columns
model_bnr_all_df.index = ['COVID', 'Normal', 'Viral Pneumonia','Total']
model_bnr_all_df
Out[80]:
Precision Recall F-Score Support
COVID 0.943231 0.900000 0.921109 240.0
Normal 0.876448 0.945833 0.909820 240.0
Viral Pneumonia 0.913793 0.883333 0.898305 240.0
Total 0.911157 0.909722 0.909744 NaN
In [81]:
##################################
# Consolidating all model evaluation metrics 
# for CNN with batch normalization regularization
##################################
model_bnr_model_list = []
model_bnr_measure_list = []
model_bnr_category_list = []
model_bnr_value_list = []

for i in range(3): 
    for j in range(4):
        model_bnr_model_list.append('CNN_BNR')
        model_bnr_measure_list.append(metric_columns[i])
        model_bnr_category_list.append(model_bnr_all_df.index[j])
        model_bnr_value_list.append(model_bnr_all_df.iloc[j,i])

model_bnr_all_summary = pd.DataFrame(zip(model_bnr_model_list,
                                        model_bnr_measure_list,
                                        model_bnr_category_list,
                                        model_bnr_value_list), 
                                        columns=['CNN.Model.Name',
                                                 'Model.Metric',
                                                 'Image.Category',
                                                 'Metric.Value'])

1.6.5 CNN With Dropout and Batch Normalization Regularization ¶

  1. The convolutional neural network model from the keras.models Python library API was implemented.
  2. The model contains 10 layers with fixed hyperparameters as follows:
    • Conv2D: conv2d
      • filters = 32
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
      • input_shape = 299x299x1
    • MaxPooling2D: max_pooling2d
      • pool_size = 2x2
    • Conv2D: conv2d_1
      • filters = 64
      • kernel_size = 3x3
      • activation = relu (rectified linear unit)
      • padding = same (output size equals input size)
    • BatchNormalization: batch_normalization
    • Activation: activation
      • activation = relu (rectified linear unit)
    • Dropout: dropout
      • rate = 0.25
    • MaxPooling2D: max_pooling2d_1
      • pool_size = 2x2
    • Flatten: flatten
    • Dense: dense
      • units = 128
      • activation = relu (rectified linear unit)
    • Dense: dense_1
      • units = 3
      • activation = softmax
  3. Additional fixed hyperparameters used during model compilation are as follows:
    • loss = categorical_crossentropy
    • optimizer = adam (adaptive moment estimation)
    • metrics = recall
  4. The model contained 44,878,979 trainable parameters broken down per layer as follows:
    • Conv2D: conv2d
      • output size = 299x299x32
      • number of parameters = 320
    • MaxPooling2D: max_pooling2d
      • output size = 149x149x32
      • number of parameters = 0
    • BatchNormalization: batch_normalization
      • output size = 149x149x64
      • number of parameters = 256
    • Activation: activation
      • output size = 149x149x64
      • number of parameters = 0
    • Dropout: dropout
      • output size = 149x149x64
      • number of parameters = 0
    • Conv2D: conv2d_1
      • output size = 149x149x64
      • number of parameters = 18496
    • MaxPooling2D: max_pooling2d_1
      • output size = 74x74x64
      • number of parameters = 0
    • Flatten: flatten
      • output size = 350464
      • number of parameters = 0
    • Dense: dense
      • output size = 128
      • number of parameters = 44859520
    • Dense: dense_1
      • output size = 3
      • number of parameters = 387
  5. The model performance on the validation set for all classes is summarized as follows:
    • Precision = 0.8842
    • Recall = 0.8736
    • F1 Score = 0.8744
In [82]:
##################################
# Formulating the network architecture
# for CNN with dropout and batch normalization regularization
##################################
set_seed()
batch_size = 16
model_dr_bnr = Sequential()
model_dr_bnr.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='Same', input_shape=(299, 299, 1)))
model_dr_bnr.add(MaxPooling2D(pool_size=(2, 2)))
model_dr_bnr.add(Conv2D(filters=64, kernel_size=(3, 3), padding='Same', activation='relu'))
model_dr_bnr.add(BatchNormalization())
model_dr_bnr.add(Activation('relu'))
model_dr_bnr.add(Dropout(0.25))
model_dr_bnr.add(MaxPooling2D(pool_size=(2, 2)))
model_dr_bnr.add(Flatten())
model_dr_bnr.add(Dense(units=128, activation='relu'))
model_dr_bnr.add(Dense(units=num_classes, activation='softmax'))

##################################
# Compiling the network layers
##################################
model_dr_bnr.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[Recall()])
In [83]:
##################################
# Displaying the model summary
# for CNN with dropout and
# batch normalization regularization
##################################
print(model_dr_bnr.summary())
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 299, 299, 32)      320       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 149, 149, 32)     0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (None, 149, 149, 64)      18496     
                                                                 
 batch_normalization (BatchN  (None, 149, 149, 64)     256       
 ormalization)                                                   
                                                                 
 activation (Activation)     (None, 149, 149, 64)      0         
                                                                 
 dropout (Dropout)           (None, 149, 149, 64)      0         
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 74, 74, 64)       0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (None, 350464)            0         
                                                                 
 dense (Dense)               (None, 128)               44859520  
                                                                 
 dense_1 (Dense)             (None, 3)                 387       
                                                                 
=================================================================
Total params: 44,878,979
Trainable params: 44,878,851
Non-trainable params: 128
_________________________________________________________________
None
In [84]:
##################################
# Displaying the model layers
# for CNN with dropout and
# batch normalization regularization
##################################
model_dr_bnr_layer_names = [layer.name for layer in model_dr_bnr.layers]
print("Layer Names:", model_dr_bnr_layer_names)
Layer Names: ['conv2d', 'max_pooling2d', 'conv2d_1', 'batch_normalization', 'activation', 'dropout', 'max_pooling2d_1', 'flatten', 'dense', 'dense_1']
In [85]:
##################################
# Displaying the number of weights
# for CNN with dropout and
# batch normalization regularization
##################################
for layer in model_dr_bnr.layers:
    if hasattr(layer, 'weights'):
        print(f"Layer: {layer.name}, Number of Weights: {len(layer.get_weights())}")
Layer: conv2d, Number of Weights: 2
Layer: max_pooling2d, Number of Weights: 0
Layer: conv2d_1, Number of Weights: 2
Layer: batch_normalization, Number of Weights: 4
Layer: activation, Number of Weights: 0
Layer: dropout, Number of Weights: 0
Layer: max_pooling2d_1, Number of Weights: 0
Layer: flatten, Number of Weights: 0
Layer: dense, Number of Weights: 2
Layer: dense_1, Number of Weights: 2
In [86]:
##################################
# Displaying the number of weights
# for CNN with dropout and
# batch normalization regularization
##################################
total_parameters = 0
for layer in model_dr_bnr.layers:
    layer_parameters = layer.count_params()
    total_parameters += layer_parameters
    print(f"Layer: {layer.name}, Parameters: {layer_parameters}")
print("\nTotal Parameters in the Model:", total_parameters)
Layer: conv2d, Parameters: 320
Layer: max_pooling2d, Parameters: 0
Layer: conv2d_1, Parameters: 18496
Layer: batch_normalization, Parameters: 256
Layer: activation, Parameters: 0
Layer: dropout, Parameters: 0
Layer: max_pooling2d_1, Parameters: 0
Layer: flatten, Parameters: 0
Layer: dense, Parameters: 44859520
Layer: dense_1, Parameters: 387

Total Parameters in the Model: 44878979
In [87]:
##################################
# Fitting the model
# for CNN with dropout and
# batch normalization regularization
##################################
epochs = 100
set_seed()
model_dr_bnr_history = model_dr_bnr.fit(train_gen,
                                        steps_per_epoch=len(train_gen) // batch_size,
                                        validation_steps=len(test_gen) // batch_size, 
                                        validation_data=test_gen, 
                                        epochs=epochs,
                                        verbose=0)
In [88]:
##################################
# Evaluating the model
# for CNN with dropout and
# batch normalization regularization
# on the independent validation set
##################################
model_dr_bnr_y_pred = model_dr_bnr.predict(test_gen)
45/45 [==============================] - 4s 97ms/step
In [89]:
##################################
# Plotting the loss profile
# for CNN with dropout and
# batch normalization regularization
# on the training and validation sets
##################################
plot_training_history(model_dr_bnr_history, 'CNN With Dropout and Batch Normalization Regularization : ')
In [90]:
##################################
# Consolidating the predictions
# for CNN with dropout and
# batch normalization regularization
# on the validation set
##################################
model_dr_bnr_predictions = np.array(list(map(lambda x: np.argmax(x), model_dr_bnr_y_pred)))
model_dr_bnr_y_true = test_gen.classes

##################################
# Formulating the confusion matrix
# for CNN with dropout and
# batch normalization regularization
# on the validation set
##################################
CMatrix = pd.DataFrame(confusion_matrix(model_dr_bnr_y_true, model_dr_bnr_predictions), columns=classes, index =classes)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with dropout and
# batch normalization regularization
# for each category of the validation set
##################################
plt.figure(figsize=(10, 6))
ax = sns.heatmap(CMatrix, annot = True, fmt = 'g' ,vmin = 0, vmax = 250,cmap = 'icefire')
ax.set_xlabel('Predicted',fontsize = 14,weight = 'bold')
ax.set_xticklabels(ax.get_xticklabels(),rotation =0)
ax.set_ylabel('Actual',fontsize = 14,weight = 'bold') 
ax.set_yticklabels(ax.get_yticklabels(),rotation =0)
ax.set_title('CNN With Dropout and Batch Normalization Regularization : Validation Set Confusion Matrix',fontsize = 16,weight = 'bold',pad=20);

##################################
# Resetting all states generated by Keras
##################################
keras.backend.clear_session()
In [91]:
##################################
# Calculating the model accuracy
# for CNN with dropout and
# batch normalization regularization
# for the entire validation set
##################################
model_dr_bnr_acc = accuracy_score(model_dr_bnr_y_true, model_dr_bnr_predictions)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with dropout and
# batch normalization regularization
# for the entire validation set
##################################
model_dr_bnr_results_all = precision_recall_fscore_support(model_dr_bnr_y_true, model_dr_bnr_predictions, average='macro',zero_division = 1)

##################################
# Calculating the model 
# Precision, Recall, F-score and Support
# for CNN with dropout and
# batch normalization regularization
# for each category of the validation set
##################################
model_dr_bnr_results_class = precision_recall_fscore_support(model_dr_bnr_y_true, model_dr_bnr_predictions, average=None, zero_division = 1)

##################################
# Consolidating all model evaluation metrics 
# for CNN with dropout and
# batch normalization regularization
##################################
metric_columns = ['Precision','Recall', 'F-Score','Support']
model_dr_bnr_all_df = pd.concat([pd.DataFrame(list(model_dr_bnr_results_class)).T,pd.DataFrame(list(model_dr_bnr_results_all)).T])
model_dr_bnr_all_df.columns = metric_columns
model_dr_bnr_all_df.index = ['COVID', 'Normal', 'Viral Pneumonia','Total']
model_dr_bnr_all_df
Out[91]:
Precision Recall F-Score Support
COVID 0.950450 0.879167 0.913420 240.0
Normal 0.779310 0.941667 0.852830 240.0
Viral Pneumonia 0.923077 0.800000 0.857143 240.0
Total 0.884279 0.873611 0.874464 NaN
In [92]:
##################################
# Consolidating all model evaluation metrics 
# for CNN with dropout and
# batch normalization regularization
##################################
model_dr_bnr_model_list = []
model_dr_bnr_measure_list = []
model_dr_bnr_category_list = []
model_dr_bnr_value_list = []

for i in range(3): 
    for j in range(4):
        model_dr_bnr_model_list.append('CNN_DR_BNR')
        model_dr_bnr_measure_list.append(metric_columns[i])
        model_dr_bnr_category_list.append(model_dr_bnr_all_df.index[j])
        model_dr_bnr_value_list.append(model_dr_bnr_all_df.iloc[j,i])

model_dr_bnr_all_summary = pd.DataFrame(zip(model_dr_bnr_model_list,
                                            model_dr_bnr_measure_list,
                                            model_dr_bnr_category_list,
                                            model_dr_bnr_value_list), 
                                        columns=['CNN.Model.Name',
                                                 'Model.Metric',
                                                 'Image.Category',
                                                 'Metric.Value'])

1.7. Consolidated Findings ¶

  1. The CNN Model With No Regularization demonstrated the following validation set performance for all image categories:
    • Precision = 0.7906
    • Recall = 0.7819
    • F1 Score = 0.7825
  2. The CNN Model With Dropout Regularization demonstrated the following validation set performance for all image categories:
    • Precision = 0.8565
    • Recall = 0.8472
    • F1 Score = 0.8457
  3. The CNN Model With Batch Normalization Regularization demonstrated the following validation set performance for all image categories:
    • Precision = 0.9111
    • Recall = 0.9097
    • F1 Score = 0.9097
  4. The CNN Model With Dropout and Batch Normalization Regularization demonstrated the following validation set performance for all image categories:
    • Precision = 0.8842
    • Recall = 0.8736
    • F1 Score = 0.8744
  5. The CNN Model With Batch Normalization Regularization had the best validation set performance and was selected among all candidate models.
    • Precision = 0.9111
    • Recall = 0.9097
    • F1 Score = 0.9097
  6. While the classification results have been sufficiently high, the current study can be further extended to achieve optimal model performance through the following:
    • Conduct model hyperparameter tuning given sufficient analysis time and higher computing power
    • Formulate deeper neural network architectures to better capture spatial hierarchies and features in the input images
    • Apply various techniques to interpret the CNN models by understanding and visualizing the features and decisions made at each layer
    • Consider an imbalanced dataset and apply remedial measures to address unbalanced classification to accurately reflect real-world scenario
In [93]:
##################################
# Consolidating all the
# CNN model performance measures
##################################
cnn_model_performance_comparison = pd.concat([model_nr_all_summary, 
                                              model_dr_all_summary,
                                              model_bnr_all_summary, 
                                              model_dr_bnr_all_summary], 
                                             ignore_index=True)
In [94]:
##################################
# Consolidating all the precision
# model performance measures
##################################
cnn_model_performance_comparison_precision = cnn_model_performance_comparison[cnn_model_performance_comparison['Model.Metric']=='Precision']
cnn_model_performance_comparison_precision_CNN_NR = cnn_model_performance_comparison_precision[cnn_model_performance_comparison_precision['CNN.Model.Name']=='CNN_NR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_precision_CNN_DR = cnn_model_performance_comparison_precision[cnn_model_performance_comparison_precision['CNN.Model.Name']=='CNN_DR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_precision_CNN_BNR = cnn_model_performance_comparison_precision[cnn_model_performance_comparison_precision['CNN.Model.Name']=='CNN_BNR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_precision_CNN_DR_BNR = cnn_model_performance_comparison_precision[cnn_model_performance_comparison_precision['CNN.Model.Name']=='CNN_DR_BNR'].loc[:,"Metric.Value"]
In [95]:
##################################
# Combining all the precision
# model performance measures
# for all CNN models
##################################
cnn_model_performance_comparison_precision_plot = pd.DataFrame({'CNN_NR': cnn_model_performance_comparison_precision_CNN_NR.values,
                                                                'CNN_DR': cnn_model_performance_comparison_precision_CNN_DR.values,
                                                                'CNN_BNR': cnn_model_performance_comparison_precision_CNN_BNR.values,
                                                                'CNN_DR_BNR': cnn_model_performance_comparison_precision_CNN_DR_BNR.values},
                                                               index=cnn_model_performance_comparison_precision['Image.Category'].unique())
cnn_model_performance_comparison_precision_plot
Out[95]:
CNN_NR CNN_DR CNN_BNR CNN_DR_BNR
COVID 0.890295 0.906504 0.943231 0.950450
Normal 0.671378 0.904255 0.876448 0.779310
Viral Pneumonia 0.810000 0.758741 0.913793 0.923077
Total 0.790558 0.856500 0.911157 0.884279
In [96]:
##################################
# Plotting all the precision
# model performance measures
# for all CNN models
##################################
cnn_model_performance_comparison_precision_plot = cnn_model_performance_comparison_precision_plot.plot.barh(figsize=(10, 6), width=0.90)
cnn_model_performance_comparison_precision_plot.set_xlim(0.00,1.00)
cnn_model_performance_comparison_precision_plot.set_title("Model Comparison by Precision Performance on Validation Data")
cnn_model_performance_comparison_precision_plot.set_xlabel("Precision Performance")
cnn_model_performance_comparison_precision_plot.set_ylabel("Image Categories")
cnn_model_performance_comparison_precision_plot.grid(False)
cnn_model_performance_comparison_precision_plot.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
for container in cnn_model_performance_comparison_precision_plot.containers:
    cnn_model_performance_comparison_precision_plot.bar_label(container, fmt='%.5f', padding=-50, color='white', fontweight='bold')
In [97]:
##################################
# Consolidating all the recall
# model performance measures
##################################
cnn_model_performance_comparison_recall = cnn_model_performance_comparison[cnn_model_performance_comparison['Model.Metric']=='Recall']
cnn_model_performance_comparison_recall_CNN_NR = cnn_model_performance_comparison_recall[cnn_model_performance_comparison_recall['CNN.Model.Name']=='CNN_NR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_recall_CNN_DR = cnn_model_performance_comparison_recall[cnn_model_performance_comparison_recall['CNN.Model.Name']=='CNN_DR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_recall_CNN_BNR = cnn_model_performance_comparison_recall[cnn_model_performance_comparison_recall['CNN.Model.Name']=='CNN_BNR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_recall_CNN_DR_BNR = cnn_model_performance_comparison_recall[cnn_model_performance_comparison_recall['CNN.Model.Name']=='CNN_DR_BNR'].loc[:,"Metric.Value"]
In [98]:
##################################
# Combining all the recall
# model performance measures
# for all CNN models
##################################
cnn_model_performance_comparison_recall_plot = pd.DataFrame({'CNN_NR': cnn_model_performance_comparison_recall_CNN_NR.values,
                                                             'CNN_DR': cnn_model_performance_comparison_recall_CNN_DR.values,
                                                             'CNN_BNR': cnn_model_performance_comparison_recall_CNN_BNR.values,
                                                             'CNN_DR_BNR': cnn_model_performance_comparison_recall_CNN_DR_BNR.values},
                                                            index=cnn_model_performance_comparison_recall['Image.Category'].unique())
cnn_model_performance_comparison_recall_plot
Out[98]:
CNN_NR CNN_DR CNN_BNR CNN_DR_BNR
COVID 0.879167 0.929167 0.900000 0.879167
Normal 0.791667 0.708333 0.945833 0.941667
Viral Pneumonia 0.675000 0.904167 0.883333 0.800000
Total 0.781944 0.847222 0.909722 0.873611
In [99]:
##################################
# Plotting all the recall
# model performance measures
# for all CNN models
##################################
cnn_model_performance_comparison_recall_plot = cnn_model_performance_comparison_recall_plot.plot.barh(figsize=(10, 6), width=0.90)
cnn_model_performance_comparison_recall_plot.set_xlim(0.00,1.00)
cnn_model_performance_comparison_recall_plot.set_title("Model Comparison by Recall Performance on Validation Data")
cnn_model_performance_comparison_recall_plot.set_xlabel("Recall Performance")
cnn_model_performance_comparison_recall_plot.set_ylabel("Image Categories")
cnn_model_performance_comparison_recall_plot.grid(False)
cnn_model_performance_comparison_recall_plot.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
for container in cnn_model_performance_comparison_recall_plot.containers:
    cnn_model_performance_comparison_recall_plot.bar_label(container, fmt='%.5f', padding=-50, color='white', fontweight='bold')
In [100]:
##################################
# Consolidating all the f-score
# model performance measures
##################################
cnn_model_performance_comparison_fscore = cnn_model_performance_comparison[cnn_model_performance_comparison['Model.Metric']=='F-Score']
cnn_model_performance_comparison_fscore_CNN_NR = cnn_model_performance_comparison_fscore[cnn_model_performance_comparison_fscore['CNN.Model.Name']=='CNN_NR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_fscore_CNN_DR = cnn_model_performance_comparison_fscore[cnn_model_performance_comparison_fscore['CNN.Model.Name']=='CNN_DR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_fscore_CNN_BNR = cnn_model_performance_comparison_fscore[cnn_model_performance_comparison_fscore['CNN.Model.Name']=='CNN_BNR'].loc[:,"Metric.Value"]
cnn_model_performance_comparison_fscore_CNN_DR_BNR = cnn_model_performance_comparison_fscore[cnn_model_performance_comparison_fscore['CNN.Model.Name']=='CNN_DR_BNR'].loc[:,"Metric.Value"]
In [101]:
##################################
# Combining all the f-score
# model performance measures
# for all CNN models
##################################
cnn_model_performance_comparison_fscore_plot = pd.DataFrame({'CNN_NR': cnn_model_performance_comparison_fscore_CNN_NR.values,
                                                             'CNN_DR': cnn_model_performance_comparison_fscore_CNN_DR.values,
                                                             'CNN_BNR': cnn_model_performance_comparison_fscore_CNN_BNR.values,
                                                             'CNN_DR_BNR': cnn_model_performance_comparison_fscore_CNN_DR_BNR.values},
                                                            index=cnn_model_performance_comparison_fscore['Image.Category'].unique())
cnn_model_performance_comparison_fscore_plot
Out[101]:
CNN_NR CNN_DR CNN_BNR CNN_DR_BNR
COVID 0.884696 0.917695 0.921109 0.913420
Normal 0.726577 0.794393 0.909820 0.852830
Viral Pneumonia 0.736364 0.825095 0.898305 0.857143
Total 0.782546 0.845728 0.909744 0.874464
In [102]:
##################################
# Plotting all the fscore
# model performance measures
# for all CNN models
##################################
cnn_model_performance_comparison_fscore_plot = cnn_model_performance_comparison_fscore_plot.plot.barh(figsize=(10, 6), width=0.90)
cnn_model_performance_comparison_fscore_plot.set_xlim(0.00,1.00)
cnn_model_performance_comparison_fscore_plot.set_title("Model Comparison by F-Score Performance on Validation Data")
cnn_model_performance_comparison_fscore_plot.set_xlabel("F-Score Performance")
cnn_model_performance_comparison_fscore_plot.set_ylabel("Image Categories")
cnn_model_performance_comparison_fscore_plot.grid(False)
cnn_model_performance_comparison_fscore_plot.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
for container in cnn_model_performance_comparison_fscore_plot.containers:
    cnn_model_performance_comparison_fscore_plot.bar_label(container, fmt='%.5f', padding=-50, color='white', fontweight='bold')

2. Summary ¶

A detailed report was formulated documenting all the analysis steps and findings.

DeepLearningProject_Introduction.png

DeepLearning_Methodology.png

DeepLearning_DataGathering.png

DeepLearning_DataDescription.png

DeepLearning_DataPreprocessing.png

DeepLearning_DataExploration.png

DeepLearning_ModelDevelopment.png

DeepLearning_ModelValidation.png

DeepLearning_ModelSelection.png

DeepLearning_Conclusion.png

3. References ¶

  • [Book] Deep Learning with Python by Francois Chollet
  • [Book] Deep Learning: A Visual Approach by Andrew Glassner
  • [Book] Learning Deep Learning by Magnus Ekman
  • [Book] Practical Deep Learning by Ronald Kneusel
  • [Book] Deep Learning with Tensorflow and Keras by Amita Kapoor, Antonio Gulli and Sujit Pal
  • [Book] Deep Learning by John Kelleher
  • [Book] Generative Deep Learning by David Foster
  • [Book] Deep Learning Illustrated by John Krohn, Grant Beyleveld and Aglae Bassens
  • [Book] Neural Networks and Deep Learning by Charu Aggarwal
  • [Book] Grokking Deep Learning by Andrew Trask
  • [Book] Deep Learning with Pytorch by Eli Stevens, Luca Antiga and Thomas Viehmann
  • [Book] Deep Learning by Ian Goodfellow, Yoshua Bengio and Aaron Courville
  • [Book] Deep Learning from Scratch by Seth Weidman
  • [Book] Fundamentals of Deep Learning by Nithin Buduma, Nikhil Buduma and Joe Papa
  • [Book] Hands-On Machine Learning with Scikit-Learn, Keras and Tensorflow by Aurelien Geron
  • [Book] Deep Learning for Computer Vision by Jason Brownlee
  • [Python Library API] numpy by NumPy Team
  • [Python Library API] pandas by Pandas Team
  • [Python Library API] seaborn by Seaborn Team
  • [Python Library API] matplotlib.pyplot by MatPlotLib Team
  • [Python Library API] matplotlib.image by MatPlotLib Team
  • [Python Library API] matplotlib.offsetbox by MatPlotLib Team
  • [Python Library API] tensorflow by TensorFlow Team
  • [Python Library API] keras by Keras Team
  • [Python Library API] pil by Pillow Team
  • [Python Library API] glob by glob Team
  • [Python Library API] cv2 by OpenCV Team
  • [Python Library API] os by os Team
  • [Python Library API] random by random Team
  • [Python Library API] keras.models by TensorFlow Team
  • [Python Library API] keras.layers by TensorFlow Team
  • [Python Library API] keras.wrappers by TensorFlow Team
  • [Python Library API] keras.utils by TensorFlow Team
  • [Python Library API] keras.optimizers by TensorFlow Team
  • [Python Library API] keras.preprocessing.image by TensorFlow Team
  • [Python Library API] keras.callbacks by TensorFlow Team
  • [Python Library API] keras.metrics by TensorFlow Team
  • [Python Library API] sklearn.metrics by Scikit-Learn Team
  • [Article] Convolutional Neural Networks, Explained by Mayank Mishra (Towards Data Science)
  • [Article] A Comprehensive Guide to Convolutional Neural Networks — the ELI5 way by Sumit Saha (Towards Data Science)
  • [Article] Understanding Convolutional Neural Networks: A Beginner’s Journey into the Architecture by Afaque Umer (Medium)
  • [Article] Introduction to Convolutional Neural Networks (CNN) by Manav Mandal (Analytics Vidhya)
  • [Article] What Are Convolutional Neural Networks? by IBM Team (IBM)
  • [Article] What is CNN? A 5 Year Old guide to Convolutional Neural Network by William Ong (Medium)
  • [Article] Convolutional Neural Network by Thomas Wood (DeepAI.Org)
  • [Article] How Do Convolutional Layers Work in Deep Learning Neural Networks? by Jason Brownlee (Machine Learning Mastery)
  • [Article] Convolutional Neural Networks Explained: Using PyTorch to Understand CNNs by Vihar Kurama (BuiltIn)
  • [Article] Convolutional Neural Networks Cheatsheet by Afshine Amidi and Shervine Amidi (Stanford University)
  • [Article] An Intuitive Explanation of Convolutional Neural Networks by Ujjwal Karn (The Data Science Blog)
  • [Article] Convolutional Neural Network by NVIDIA Team (NVIDIA)
  • [Article] Convolutional Neural Networks (CNN) Overview by Nikolaj Buhl (Encord)
  • [Article] Understanding Convolutional Neural Network (CNN): A Complete Guide by LearnOpenCV Team (LearnOpenCV)
  • [Article] Convolutional Neural Networks (CNNs) and Layer Types by Adrian Rosebrock (PyImageSearch)
  • [Article] How Convolutional Neural Networks See The World by Francois Chollet (The Keras Blog)
  • [Article] What Is a Convolutional Neural Network? by MathWorks Team (MathWorks)
  • [Kaggle Project] Covid 19 Radiography Data - EDA and CNN Model by Juliana Negrini De Araujo (Kaggle)
  • [Kaggle Project] Pneumonia Detection using CNN (92.6% Accuracy) by Madhav Mathur (Kaggle)
  • [Kaggle Project] COVID Detection from CXR Using Explainable CNN by Manu Siddhartha (Kaggle)
  • [Kaggle Project] Class Activation Mapping for COVID-19 CNN by Amy Zhang (Kaggle)
  • [Kaggle Project] CNN XRay COVID Classification by Gabriel Mino (Kaggle)
  • [Kaggle Project] Detecting-Covid-19-Images | CNN by Felipe Oliveira (Kaggle)
  • [Kaggle Project] Detection of Covid Positive Cases using DL by Sana Shaikh (Kaggle)
  • [Kaggle Project] Deep Learning and Transfer Learning on COVID-19 by Digvijay Yadav (Kaggle)
  • [Kaggle Project] X-ray Detecting Using CNN by Shivan Kumar (Kaggle)
  • [Kaggle Project] Classification of COVID-19 using CNN by Islam Selim (Kaggle)
  • [Kaggle Project] COVID-19 - Revisiting Pneumonia Detection by Paulo Breviglieri (Kaggle)
  • [Kaggle Project] Multi-Class X-ray Covid19 Classification-94% Accurary by Derrel Souza (Kaggle)
  • [Publication] Gradient-Based Learning Applied to Document Recognition by Yann LeCun, Leon Bottou, Yoshua Bengio and Patrick Haffner (Proceedings of the IEEE)
In [103]:
from IPython.display import display, HTML
display(HTML("<style>.rendered_html { font-size: 15px; font-family: 'Trebuchet MS'; }</style>"))